﻿using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Development.Tools;
using System.Collections.Generic;
using Development.Network.Msg;

namespace Development.Network.AsycnSocket
{
    /// <summary>
    /// 异步 socket 服务器
    /// </summary>
    public class AsyncSocketServer
    {
        private Socket m_listenSocket;                      //监听的socket
        private int m_numConnections; //最大支持连接个数
        private int m_receiveBufferSize; //每个连接接收缓存大小

        private int m_socketTimeOutMS = 30000;                      //Socket最大超时时间，单位为MS 为30秒
        private System.Timers.Timer m_heartTime;
        public int SocketTimeOutMS { get { return m_socketTimeOutMS; } }


        private AsycnTokenManager m_asyncUserTokenMananger;

        public AsycnTokenManager UserTokenManager{ get { return m_asyncUserTokenMananger; } }


        public AsyncSocketServer(int numConnections, int recvBufferSize)
        {
            m_numConnections = numConnections;
            m_receiveBufferSize = recvBufferSize;

            m_asyncUserTokenMananger = new AsycnTokenManager();
            Init();
        }

        /// <summary>
        /// 初始化服务器
        /// </summary>
        private void Init()
        {
            //按照连接数建立读写对象
            AsyncUserToken userToken;
            for (int i = 0; i < m_numConnections; ++i)
            {
                userToken = AsyncUserToken.CreateUserToken(m_receiveBufferSize, this);
                userToken.ReceiveEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
                userToken.SendEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
                m_asyncUserTokenMananger.Push(userToken);
            }
        }


        public bool Listen(int port, string ip = null)
        {
            IPEndPoint point = null;
            if (string.IsNullOrEmpty(ip))
            {
                point = new IPEndPoint(IPAddress.Any, port);
            }
            else
            {
                point = new IPEndPoint(IPAddress.Parse(ip), port);
            }
            try
            {
                m_listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                m_listenSocket.Bind(point);
                m_listenSocket.Listen(m_numConnections);
                Log.WriteLog(ELogLevel.LOG_INFO, string.Format("socket listen port: {0} success", port));
                for (int i = 0; i < 20;++i )
                {
                    PostAccept(null);
                }
                StartHearJump();
            }
            catch (SocketException e)
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, string.Format("{0};info[instance:{1}methed:{2}stack:{3}", e.Message, e.Source, e.TargetSite.Name, e.StackTrace));
                return false;
            }
            return true;
        }

        private void StartHearJump()
        {
            m_heartTime = new System.Timers.Timer(30000);
            m_heartTime.Elapsed += m_heartTime_Elapsed;
            m_heartTime.Start();
        }

        void m_heartTime_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            List<AsyncUserToken> userList = m_asyncUserTokenMananger.GetList();
            foreach (AsyncUserToken user in userList)
            {
                lock (user)
                {
                    if ((DateTime.Now - user.ActiveDateTime).TotalMilliseconds > m_socketTimeOutMS)
                    {
                        CloseClientSocket(user);
                    }
                }
            }
        }



        /// <summary>
        /// 投递接受连接
        /// </summary>
        /// <param name="acceptEventArgs"></param>
        private void PostAccept(SocketAsyncEventArgs acceptEventArgs)
        {
            if (acceptEventArgs == null)
            {
                acceptEventArgs = new SocketAsyncEventArgs();
                acceptEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
            }
            else
            {
                acceptEventArgs.AcceptSocket = null; //释放上次绑定的Socket，等待下一个Socket连接
            }
            try
            {
                bool willRaiseEvent = m_listenSocket.AcceptAsync(acceptEventArgs);
                if (!willRaiseEvent)
                {
                    ProcessAccept(acceptEventArgs);
                }
            }
            catch(Exception)
            { }
          
        }

        /// <summary>
        /// 处理连接
        /// </summary>
        /// <param name="acceptEventArgs"></param>
        private void ProcessAccept(SocketAsyncEventArgs acceptEventArgs)
        {
            AsyncUserToken userToken = m_asyncUserTokenMananger.Pop();
            if (userToken == null)
            {
                //缓存已用尽，放掉连接
                Log.WriteLog(ELogLevel.LOG_INFO, "user token pool empty");
                acceptEventArgs.AcceptSocket.Close();
                return;
            }
            userToken.ConnectSocket = acceptEventArgs.AcceptSocket;
            userToken.ConnectDateTime = DateTime.Now;
            PostReceive(userToken.ReceiveEventArgs);
            Log.WriteLog(ELogLevel.LOG_INFO, string.Format("client connection {0},curr count = {1}", acceptEventArgs.AcceptSocket.RemoteEndPoint, m_asyncUserTokenMananger.Count()));
        }

        /// <summary>
        /// 接受连接处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="acceptEventArgs"></param>
        void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs acceptEventArgs)
        {
            try
            {
                if (acceptEventArgs.AcceptSocket != null && acceptEventArgs.SocketError == SocketError.Success)
                {
                    ProcessAccept(acceptEventArgs);
                }
            }
            catch (Exception E)
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, string.Format("Accept client {0} error, message: {1}", acceptEventArgs.AcceptSocket, E.Message));
            }
            finally
            {
                PostAccept(acceptEventArgs); //把当前异步事件释放，等待下次连接
            }
        }

        /// <summary>
        /// 投递接收数据
        /// </summary>
        /// <param name="userToken"></param>
        private void PostReceive(SocketAsyncEventArgs receiveEventArgs)
        {
            AsyncUserToken userToken = receiveEventArgs.UserToken as AsyncUserToken;
            try
            {
                bool willRaiseEvent = userToken.ConnectSocket.ReceiveAsync(userToken.ReceiveEventArgs); //投递接收请求
                if (!willRaiseEvent)
                {
                    lock (userToken)
                    {
                        ProcessReceive(userToken.ReceiveEventArgs);
                    }
                }
            }
            catch (Exception)
            {
                CloseClientSocket(userToken);
            }
        }


        /// <summary>
        /// 处理接受的数据
        /// </summary>
        /// <param name="receiveEventArgs"></param>
        private void ProcessReceive(SocketAsyncEventArgs receiveEventArgs)
        {
            AsyncUserToken userToken = receiveEventArgs.UserToken as AsyncUserToken;
            if (userToken.ConnectSocket == null)
            {
                return;
            }
            if (userToken.ReceiveEventArgs.BytesTransferred > 0 && userToken.ReceiveEventArgs.SocketError == SocketError.Success)
            {

                userToken.ReceiveBuffer.WriteBuffer(userToken.AsyncReceiveBuffer, 0, userToken.ReceiveEventArgs.BytesTransferred);
                //开始解包
                //前四个字节为包的长度，后面的内容是协议数据
                while (userToken.ReceiveBuffer.DataCount >= 4)
                {
                    int packetLength = BitConverter.ToInt32(userToken.ReceiveBuffer.Buffer, 0);
                    if ((packetLength <= 0) || (packetLength > 10 * 1024 * 1024) || (userToken.ReceiveBuffer.DataCount > 10 * 1024 * 1024))
                    {
                        //异常包
                        CloseClientSocket(userToken);
                        return;
                    }

                    //消息报长度不够，等待下一次处理
                    if (userToken.ReceiveBuffer.DataCount < packetLength)
                    {
                        break;
                    }
                    else
                    {
                        //解析包
                        MsgPacket msg = MsgPacket.SplitPacket(userToken,userToken.ReceiveBuffer.Buffer, 0, packetLength);
                        Routiner.Instance.AddMsgPacket(msg);
                        //处理完消息包，重置缓存
                        userToken.ReceiveBuffer.Clear(packetLength);
                    }

                }
                //继续投递接收消息
                PostReceive(receiveEventArgs);
            }
            else
            {
                CloseClientSocket(userToken);
            }
        }


        /// <summary>
        /// 处理发送事件
        /// </summary>
        /// <param name="sendEventArgs"></param>
        /// <returns></returns>
        private void ProcessSend(SocketAsyncEventArgs sendEventArgs)
        {
            AsyncUserToken userToken = sendEventArgs.UserToken as AsyncUserToken;
            if (userToken.ConnectSocket == null)
            {
                return;
            }
            if (sendEventArgs.BytesTransferred != 0 && sendEventArgs.SocketError == SocketError.Success)
            {
                userToken.SendCompleted(sendEventArgs.BytesTransferred); //调用子类回调函数
            }
            else
            {
                CloseClientSocket(userToken);
            }
        }

        public void SendAsyncEvent(Socket connectSocket, SocketAsyncEventArgs sendEventArgs)
        {
            try
            {
                bool willRaiseEvent = connectSocket.SendAsync(sendEventArgs);
                if (!willRaiseEvent)
                {
                    ProcessSend(sendEventArgs);
                }
            }
            catch (Exception) { }
        }



        /// <summary>
        /// io处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="asyncEventArgs"></param>
        void IO_Completed(object sender, SocketAsyncEventArgs asyncEventArgs)
        {
            AsyncUserToken userToken = asyncEventArgs.UserToken as AsyncUserToken;
            userToken.ActiveDateTime = DateTime.Now;
            lock (userToken)
            {
                try
                {

                    if (asyncEventArgs.LastOperation == SocketAsyncOperation.Receive)
                        ProcessReceive(asyncEventArgs);
                    else if (asyncEventArgs.LastOperation == SocketAsyncOperation.Send)
                        ProcessSend(asyncEventArgs);
                    else
                        throw new ArgumentException("The last operation completed on the socket was not a receive or send");
                }
                catch (Exception E)
                {
                    Log.WriteLog(ELogLevel.LOG_ERROR, E);
                    CloseClientSocket(userToken);
                }
            }
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        /// <param name="userToken"></param>
        public void CloseClientSocket(AsyncUserToken userToken)
        {
            try
            {
                if(userToken.ConnectSocket != null)
                {
                    userToken.ConnectSocket.Shutdown(SocketShutdown.Both);
                }
                else
                {
                    return;
                }
            }
            catch (Exception e)
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, string.Format("CloseClientSocket Disconnect client {0} error, message: {1}", userToken.ConnectSocket.RemoteEndPoint, e.Message));
            }
            m_asyncUserTokenMananger.Push(userToken);
            Log.WriteLog(ELogLevel.LOG_INFO, string.Format("client disconnection {0},curr count = {1}", userToken.ConnectSocket.RemoteEndPoint, m_asyncUserTokenMananger.Count()));
            userToken.Clear();
        }


        public void CloseListen()
        {
            m_heartTime.Stop();
            m_listenSocket.Close();
        }

    }
}
